﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;

namespace UserInterface
{
    [Serializable()]
    public class Car : MovingObject
    {
        /// <summary>
        /// The <b>Current </b> Lane that the car is moving in.
        /// <remarks>The car might be moving inside the BlackBox,
        /// <br />but still having a departure lane considered the current one</remarks>
        /// </summary>
        public Lane departure
        {
            get { return this.depart; }
            set { this.depart = value; }
        }
        /// <summary>
        /// randomizer for the speed of the car
        /// </summary>
        Random rdm = new Random();

        /// <summary>
        /// Occurs when the car reaches the inner boundaries of the lane
        /// </summary>
        public event Move moveLane;

        /// <summary>
        /// Occurs when the car reaches the outer boundaries of the lane and crossing
        /// </summary>
        public event Change changeCrossing;
        

        /// <summary>
        /// The destination lane of <b>this </b>Car.
        /// </summary>
        /// <remarks>Where it's going.</remarks>
        public Lane destination
        {
            get { return this.desti; }
            set { this.desti = value; }
        }
        
        /// <summary>
        /// The current position of the Car
        /// </summary>
        public Point position
        {
            get { return this.pos; }
            set { this.pos = value; }
        }

        /// <summary>
        /// Defines if the car is moving inside the BlackBox or Not.
        /// </summary>
        public Boolean isOnBlckbx
        {
            get;
            set;
        }
        /// <summary>
        /// The speed of the car in coordinates of X or Y
        /// </summary>
        public int speed { get { return this.spd; } set { this.spd = value; } }

        /// <summary>
        /// Empty constructor
        /// </summary>
        public Car()
        { }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="depLane">the departure lane</param>
        /// <param name="destLane">the destination lane</param>
        /// <param name="toMove">the move function</param>
        /// <param name="toCrossing">the change to crossing function</param>
        public Car(Lane depLane, Lane destLane, Move toMove, Change toCrossing)
        {
            this.depart = depLane;
            this.desti = destLane;
            this.pos = depart.start;
            this.spd = rdm.Next(2,4);
            this.isOnBlckbx = false;
            
            if(toMove !=null)
                moveLane += new Move(toMove);
            
            if(toCrossing != null)
                changeCrossing += new Change(toCrossing);
        }

        /// <summary>
        /// <b>Finished</b>
        /// Is called when you want to move this car.
        /// Defines whether to move on the BlackBox or the lane.
        /// </summary>
        /// <param name="id">The name of the curent lane</param>
        /// <param name="end">The starting point of the destination lane</param>
        /// <param name="parent">The type of crossing that holds the current lane</param>
        /// <param name="canMove">If it is the first car in the list and has a green light</param>
        public void move(string id, Point end, Parent parent, bool canMove)
        {

            if (isOnBlckbx)
            {  //if (Lane.TLight.color == Color.Green)
               moveOnBlackBox(id, end, parent);
            }
            else moveONLane(id, end, canMove); 
            
        }

        /// <summary>
        /// Moves the car according to specific coordinates.
        /// Switches according to the direction and 
        /// defines specific x and y patterns to move the car inside the middle of the crossing.
        /// The <b>BlackBox</b>
        /// </summary>
        /// <param name="laneName">The name of the lane that defines the direction</param>
        /// <param name="end">The point to reach.<br />The ending point of the lane or the cars in front</param>
        /// <param name="parent">The type of crossing that the lane is in </param>
        public void moveOnBlackBox(string laneName, Point end, Parent parent)
        {
            if (parent == Parent.Type2)
            {
                switch (laneName)
                { 
                    case "N1-E3": // Downwards and right
                         if (this.position.Y < end.Y && this.position.Y + spd < end.Y)
                        {
                            if (this.position.Y < 150)
                                this.pos.Y += spd;
                           
                            else if (this.position.Y >= 150 && this.position.Y < 210)
                            {
                                this.pos.X += spd;
                                this.pos.Y += spd;
                            }
                            else if (this.position.Y >= 210)
                                this.pos.X += spd;                            
                           return;
                         }

                         this.moveLane(this);
                        return;

                    case "N1-S1": // Downwards
                        if (this.position.Y < end.Y && this.position.Y + spd < end.Y)                              
                        {        
                            this.pos.Y += spd;
                           return;
                        }
                        else if (this.position.Y + spd >= end.Y) 

                         this.moveLane(this);

                        return;

                    case "N1-W1": // a bit Downwards and Left
                        if (this.position.Y < end.Y && this.position.Y + spd < end.Y && this.position.X > end.X )
                        {
                            if (this.position.Y < 110)
                            {
                                this.pos.Y += spd;
                                this.pos.X--;
                            }
                            else if (this.position.Y >= 110 && this.position.X > end.X)
                            {
                                this.pos.X -= spd;                                
                            }
                            else if (this.position.X > end.X)
                                this.pos.X -= spd;
                            return;
                        }
                            this.moveLane(this);
                        return;

                    case "E1-N3": //a bit straight and Upwards

                        if (this.position.X > end.X && this.position.X - spd > end.X)
                        {
                            if (this.position.X > 190)
                            {
                                this.pos.X -= spd;
                                this.pos.Y--;
                                return;
                            }
                        }
                        
                        if (this.position.Y > end.Y && this.position.Y - spd > end.Y)
                        {
                            this.pos.X--;
                            this.pos.Y -= spd;
                            return;
                        }
                        else
                            this.moveLane(this);

                        break;
                    case "E1-W1": // Straigth and a bit Up

                        if (this.position.X > end.X && this.position.X - spd > end.X)
                        {
                            this.pos.X -= spd;
                            if (this.position.Y > 115 && this.position.X < 150)
                                    this.pos.Y--;
                            return;
                        }
                        else if (this.position.X - spd <= end.X)
                            
                         this.moveLane(this);

                        return;
                    case "E2-S1": // Left and Downwards

                        if (this.position.X > end.X && this.position.X - spd > end.X)
                        {
                            if (this.position.X > 140)
                            {
                                this.pos.X -= spd;
                                if (pos.X < 155)
                                    this.pos.Y++;
                                return;
                            }
                            if (this.position.Y < end.Y && this.position.Y + spd < end.Y)
                            {
                                if (pos.X > 125 && pos.X - 1 >= end.X)
                                    this.pos.X--;
                                this.pos.Y += spd;
                                return;
                            }
                        }

                            else
                                this.moveLane(this);
                                                    
                        break;

                    case "S2-W1": // Upwards and left

                        if (this.position.Y > end.Y && this.position.Y - spd > end.Y)
                        {
                            if (this.position.Y > 140)
                            {
                                this.pos.Y -= spd;
                                this.pos.X--;
                            }
                            else if (this.position.Y <= 140  && this.position.Y > 125)
                            {
                                this.pos.X -=spd;
                                this.pos.Y-=spd;
                            }
                            else if (this.position.Y <= 125)
                                this.pos.X -= spd;                            
                           return;
                         }

                         this.moveLane(this);
                        return;

                    case "S2-N3": // Upwards
                        if (this.position.Y > end.Y && this.position.Y + spd > end.Y)                              
                        {        
                            this.pos.Y -= spd;
                           return;
                        }
                        else if (this.position.Y - spd < end.Y) 

                         this.moveLane(this);

                        return;

                    case "S2-E3": // a bit straight and Upwards
                        
                        if (this.position.Y > end.Y && this.position.Y - spd > end.Y)
                        {
                            if (this.position.Y > 190)
                            {
                                this.pos.Y -= spd;
                                this.pos.X++;
                            }                        
                            else if (this.position.Y >= end.Y && this.position.X + spd < end.X)
                            {
                                this.pos.X += spd;
                                if(this.pos.Y > end.Y)
                                this.pos.Y--;
                                return;
                            }

                        }
                        else
                            this.moveLane(this);
                        break;

                    case "W2-N3": // Upwards and left

                        if (this.position.X < end.X && this.position.X + spd < end.X)
                        {
                            this.pos.X += spd;
                            if (pos.X >= 150)
                                pos.Y--;
                            return;
                        }
                        else if (this.position.Y > end.Y && this.position.Y+spd > end.Y)
                        {
                            this.pos.Y -= spd;
                            return;
                        }
                            this.moveLane(this);

                        return;

                    case "W3-S1": // a bit straight and Downwards
                        if (this.position.X < end.X && this.position.X + spd < end.X)
                        {
                            this.pos.X += spd;
                            if (pos.X >= 100)
                                pos.Y++;
                            return;
                        }
                        else if (this.position.Y < end.Y && this.position.Y+spd < end.Y)
                        {
                            this.pos.Y += spd;
                            return;
                        }
                            this.moveLane(this);

                        break;
                    case "W3-E3": // Straight
                        if (this.position.X < end.X && this.position.X + spd < end.X)                              
                        {        
                            this.pos.X += spd;
                           return;
                        }
                        else if (this.position.X + spd >= end.X) 

                         this.moveLane(this);

                        break;
                }
            }
 //-------------------------------------------------------------------------------------------------------------------------
            else // Crossing Type 1 is on the Map 
            {
                switch (laneName)
                {
                    case "N1-W1": // a bit down and left
                       
                        if (this.position.Y < end.Y && this.position.Y + spd < end.Y && this.position.X > end.X )
                        {
                            if (this.position.Y < 120)
                            {
                                this.pos.Y += spd;
                                this.pos.X--;
                            }
                            else if (this.position.Y >= 120 && this.position.X > end.X)
                            {
                                this.pos.X -= spd;                                
                            }
                            return;
                        }
                            this.moveLane(this);
                        return;

                    case "N2-E3": // down and right
                        if (this.position.Y < end.Y && this.position.Y + spd < end.Y)
                        {
                            if (this.position.Y < 140)
                                this.pos.Y += spd;
                           
                            else if (this.position.Y >= 140 && this.position.Y < 210)
                            {
                                this.pos.X += spd;
                                this.pos.Y += spd;
                            }
                            else if (this.position.Y >= 210)
                                this.pos.X += spd;                            
                           return;
                         }

                         this.moveLane(this);
                        return;
                    case "N2-S1": // down and a bit left
                        if (this.position.Y < end.Y && this.position.Y + spd + 20 < end.Y)                              
                        {        
                            this.pos.Y += spd;
                            if (this.position.X > end.X && this.position.X-1 > end.X)
                                this.pos.X--;
                           return;
                        }
                        else if (this.position.Y + spd+ 20 >= end.Y) 

                         this.moveLane(this);

                        return;
                    case "E1-N3": // a bit left and up
                       
                        if (this.position.X > end.X && this.position.X - spd > end.X)
                        {
                            if (this.position.X > 190)
                            {
                                this.pos.X -= spd;
                                this.pos.Y--;
                                return;
                            }
                        }
                        
                        if (this.position.Y > end.Y && this.position.Y - spd > end.Y)
                        {
                            if(this.pos.X > end.X)
                                this.pos.X--;
                            this.pos.Y -= spd;
                            return;
                        }
                       
                            this.moveLane(this);

                        break;
                    case "E2-W1": // left and a bit up
                        
                        if (this.position.X > end.X && this.position.X - spd > end.X)
                        {
                            this.pos.X -= spd;
                            if (this.position.Y > 125 && this.position.X < 150)
                                    this.pos.Y-=spd;
                            return;
                        }                            
                         this.moveLane(this);

                        return;
                    case "E2-S1": // left and down
                        if (this.position.X > end.X && this.position.X - spd > end.X)
                        {
                            if (this.position.X > 140)
                            {
                                this.pos.X -= spd;
                                
                                if (pos.X > 150)
                                    this.pos.Y++;
                                return;
                            }
                            if (this.position.Y < end.Y && this.position.Y + spd < end.Y)
                            {
                                if (pos.X > end.X && pos.X - spd >= end.X)
                                    this.pos.X -= spd;
                                else if (pos.X > end.X)
                                    this.pos.X--;
                                this.pos.Y += spd;
                                return;
                            }
                        }

                            else
                                this.moveLane(this);
                                                    
                        break;
                    case "S2-W1": // up and left
                        if (this.position.Y > end.Y && this.position.Y - spd > end.Y)
                        {
                            this.pos.Y -= spd;
                            if (this.pos.X > end.X)
                                this.pos.X--;
                            return;
                        }
                        if (this.position.X > end.X)
                        {
                            this.pos.X -= spd;
                            return;
                        }
                        this.moveLane(this);
                        break;
                    case "S2-N3": // up and a bit right
                       
                        if (this.position.Y > end.Y && this.position.Y - spd -20 > end.Y)
                        {
                            this.pos.Y -= spd;
                            if (this.pos.X < end.X)
                                this.pos.X++;
                            return;
                        }
                        this.moveLane(this);
                        break;
                    case "S3-E3": // a bit up and right
                        if (this.position.Y > end.Y && this.position.Y - spd > end.Y)
                        {
                            if (this.position.Y > 210)
                            {
                                this.pos.Y -= spd;
                                if (this.position.Y < 205)
                                    this.pos.X++;
                            }                        
                            else if (this.position.Y >= end.Y && this.position.X + spd< end.X)
                            {
                                this.pos.X += spd;
                                if(this.pos.Y > end.Y)
                                this.pos.Y--;
                                return;
                            }

                        }
                        else
                            this.moveLane(this);
                        break;
                    case "W2-N3": // right and up
                        
                        if (this.position.X < end.X && this.position.X + spd < end.X)
                        {
                            this.pos.X += spd;
                            if (pos.X >= 130)
                                pos.Y-=spd;
                            return;
                        }
                        else if (this.position.Y > end.Y && this.position.Y+spd > end.Y)
                        {
                            this.pos.Y -= spd;
                            return;
                        }
                            this.moveLane(this);

                        return;

                    case "W2-E3": // right and a bit down
                    case "W3-S1": // a bit right and down
                         if (this.position.X < end.X && this.position.X + spd < end.X)
                        {
                            this.pos.X += spd;
                            if (pos.X >= 100)
                                pos.Y++;
                            return;
                        }
                        else if (this.position.Y < end.Y && this.position.Y+spd+20< end.Y)
                        {
                            this.pos.Y += spd;
                            return;
                        }
                            this.moveLane(this);

                        break;
                }
            }

            
            return;
        }
        
        /// <summary>
        /// Moves the Car inside the current Lane
        /// <br>switches through  specific X and Y patterns according the direction</br>
        /// <br>When the car moves out of the lanes boundaries changes the property </br><seealso cref="isOnBlckbx"/>
        /// </summary>
        /// <param name="id">The id of the current lane</param>
        /// <param name="end">The end point to be reached</param>
        /// <param name="canMove">A boolean that allows the car to trigger the move event</param>
        public void moveONLane(string id, Point end, bool canMove)
        {
            int tempMaxCars;
            
                switch (id)
                {
                    case "N1":
                    case "N2":
                        tempMaxCars = departure.MAXCARS;
                        if (this.position.Y < end.Y && this.position.Y + spd < end.Y && this.position.Y < 10)
                        {
                            if (this.departure.parent == Parent.Type2 && this.departure.hasPedestrians())
                            {
                                end.Y = 10; canMove = false;
                                departure.MAXCARS = 3;
                            }
                        }

                        if (this.position.Y < end.Y && this.position.Y + spd < end.Y)
                        { this.pos.Y += spd; departure.MAXCARS = tempMaxCars; return; }
                        
                        if (canMove)
                            { this.moveLane(this); }
                        return;
                        
                    case "S1":
                        if (this.position.Y < end.Y && this.position.Y + spd < end.Y && this.position.Y < 255)
                        {
                            if (this.departure.parent == Parent.Type2 && this.departure.hasPedestrians())
                            {
                                end.Y = 255; canMove = false;
                            }
                        }

                        if (this.position.Y < end.Y && this.position.Y + spd < end.Y)
                        { this.pos.Y += spd;  return; }
                        
                        if (canMove)
                        { this.changeCrossing(this); }
                        return;
                        

                    case "N3":
                        if (this.position.Y > end.Y && this.position.Y - spd > end.Y && this.position.Y > 60)
                        {
                            if (this.departure.parent == Parent.Type2 && this.departure.hasPedestrians())
                            { 
                                end.Y = 60; canMove = false; 
                            }
                        }
                        if (this.position.Y > end.Y && this.position.Y - spd > end.Y)
                        { 
                            this.pos.Y -= spd;  
                            return; 
                        }

                        if (canMove)
                            this.changeCrossing(this);
                           return;

                    case "S2":
                    case "S3":
                        if (this.position.Y > end.Y && this.position.Y - spd > end.Y && this.position.Y > 305)
                        {
                            if (this.departure.parent == Parent.Type2 && this.departure.hasPedestrians())
                            { 
                                end.Y = 305; canMove = false; 
                            }
                        }

                        if (this.position.Y > end.Y && this.position.Y - spd > end.Y)
                        { this.pos.Y -= spd; return; }
                       
                        if (canMove)
                            this.moveLane(this);
                        return;                        

                    case "E3":
                            if (this.position.X < end.X && this.position.X + spd < end.X)
                            { this.pos.X += spd; return; }
                        
                            if (canMove)
                                 this.changeCrossing(this);
                               return;

                    case "W2":
                    case "W3":

                        if (this.position.X < end.X && this.position.X + spd < end.X)
                        { this.pos.X += spd; return; }
                      
                        if(canMove)
                            this.moveLane(this);
                            return;
                       
                    case "W1":
                        if (this.position.X >= end.X && this.position.X-spd > end.X)
                        { this.pos.X -= spd; return; }
                      
                        if (canMove)
                            this.changeCrossing(this);
                            return;
                    
                    case "E1":
                    case "E2":
                        if (this.position.X >= end.X && this.position.X-spd > end.X)
                        { this.pos.X -= spd; return; }
                        if(canMove)
                            this.moveLane(this);
                            return;
                    
                    default:
                        return;
                        
             }
         }    
             
            
    }
}
    
